package com.cicc.springboot.service.impl;


import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cicc.springboot.common.dto.R;
import com.cicc.springboot.entity.MaterialZmaraEntity;
import com.cicc.springboot.entity.OrderItemEntity;
import com.cicc.springboot.entity.PurchaseOrderEntity;
import com.cicc.springboot.mapper.MaterialInformationMapper;
import com.cicc.springboot.mapper.OrderItemMapper;
import com.cicc.springboot.mapper.PurchaseOrderMapper;
import com.cicc.springboot.utile.GenericExcelListener;
import com.cicc.springboot.utile.MaterialExcelListener;
import com.cicc.springboot.utile.OrderDetailListener;
import com.cicc.springboot.utile.OrderInfoListener;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.logging.ErrorManager;
import java.util.stream.Collectors;

/**
 * Excel文件的导入导出实现类
 *
 * @ClassName GenericExcelImportServiceImpl
 * @Description TODO
 * @Author 转轮王
 * @Date 2024/9/30 10:16
 * @Version 1.0
 */

@Service
public class GenericExcelImportServiceImpl<T> {


    @Autowired
    private MaterialInformationMapper materialInformationMapper;

    @Autowired
    private PurchaseOrderMapper purchaseOrderMapper;

    @Autowired
    private OrderItemMapper orderItemMapper;


    private final int rows = 0;

    /**
     * 物料表的Excel的导入
     *
     * @param file
     * @return
     * @throws IOException
     */
    public R<String> importExcelData(MultipartFile file) throws IOException {
        // 使用泛型监听器，传入 MaterialInformationMapper、物料号提取器和查询条件
        GenericExcelListener<MaterialZmaraEntity> listener = new GenericExcelListener<>(
                materialInformationMapper,
                MaterialZmaraEntity::getMatnr,  //提取物料号进行条件查询
                data -> new LambdaQueryWrapper<MaterialZmaraEntity>().eq(MaterialZmaraEntity::getMatnr, data.getMatnr())
        );
        // 使用EasyExcel读取文
        EasyExcel.read(file.getInputStream(), MaterialZmaraEntity.class, listener)
                .sheet(0)
                .headRowNumber(1)
                .doRead();

        return R.ok(listener.getResponseMessage());
    }


    /**
     * 物料表Excel文件的批量导出
     *
     * @param ids
     * @throws IOException
     */
    public void exportExcelData(List<Long> ids) throws IOException {
        // 通过 MyBatis Plus 根据前端传来的 ID 批量查询记录
        QueryWrapper<MaterialZmaraEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id", ids);
        List<MaterialZmaraEntity> demoDataList = materialInformationMapper.selectList(queryWrapper);

        System.out.println(demoDataList.toString());

        // 指定文件保存目录
        String directoryPath = "D:/exports/";

        // 检查目录是否存在，如果不存在则创建
        File directory = new File(directoryPath);
        if (!directory.exists()) {
            directory.mkdirs();  // 创建目录
        }

        // 创建文件名和文件路径
        String fileName = "DemoData_" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".xlsx";
        String filePath = directoryPath + fileName;

        // 使用 EasyExcel 导出数据到 Excel 文件
        EasyExcel.write(filePath, MaterialZmaraEntity.class)
                .sheet("Sheet1")  // 指定要写入的 sheet 名称
                .doWrite(demoDataList);

        System.out.println("Excel 文件导出成功，文件路径：" + filePath);
    }


    /**
     * 导出物料表Excel模板
     *
     * @throws IOException
     */

    public byte[] generateExcelTemplate() throws IOException {
        // 使用 ByteArrayOutputStream 将 Excel 文件写入字节流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        // 创建一个空的数据列表，只导出表头
        List<MaterialZmaraEntity> emptyList = new ArrayList<>();

        // 使用 EasyExcel 将模板写入 ByteArrayOutputStream
        EasyExcel.write(outputStream, MaterialZmaraEntity.class)
                .sheet("物料表模板")
                .doWrite(emptyList);

        // 将字节流转换为字节数组并返回
        return outputStream.toByteArray();

    }


    /**
     * 采购订单表的Excel导入
     *
     * @param file
     * @return
     */

    @Transactional
    public R<String> importExcel(MultipartFile file) {
        try {
            InputStream purchaseOrderStream = file.getInputStream();

            // 导入第一个 sheet（采购订单）
            ImportParams purchaseOrderParams = new ImportParams();
            purchaseOrderParams.setHeadRows(1); // 设置表头为1行
            purchaseOrderParams.setStartSheetIndex(0); // 读取第一个 sheet

            List<PurchaseOrderEntity> purchaseOrders = ExcelImportUtil.importExcel(purchaseOrderStream, PurchaseOrderEntity.class, purchaseOrderParams);

            if (purchaseOrders == null || purchaseOrders.isEmpty()) {
                return R.failed("导入失败，第一张表没有数据");
            }

            // 使用 Set 来过滤掉 Excel 中重复的订单号
            Set<String> uniqueOrderCodes = new HashSet<>();
            List<PurchaseOrderEntity> filteredOrders = purchaseOrders.stream()
                    .filter(order -> order != null && order.getOrderCode() != null)
                    .filter(order -> uniqueOrderCodes.add(order.getOrderCode())) // 过滤掉重复的订单号
                    .collect(Collectors.toList());

            if (filteredOrders.isEmpty()) {
                return R.failed("导入失败，所有订单号均为重复值");
            }

            // 使用 MyBatis Plus 查询数据库中已经存在的订单号
            List<PurchaseOrderEntity> existingOrders = purchaseOrderMapper.selectList(
                    new LambdaQueryWrapper<PurchaseOrderEntity>()
                            .in(PurchaseOrderEntity::getOrderCode, uniqueOrderCodes)
            );

            // 提取已存在的订单号
            Set<String> existingOrderCodes = existingOrders.stream()
                    .map(PurchaseOrderEntity::getOrderCode)
                    .collect(Collectors.toSet());

            // 过滤掉已经在数据库中的订单号
            List<PurchaseOrderEntity> nonExistingOrders = filteredOrders.stream()
                    .filter(order -> !existingOrderCodes.contains(order.getOrderCode()))
                    .collect(Collectors.toList());

            // 如果过滤后没有剩余订单，返回错误
            if (nonExistingOrders.isEmpty()) {
                return R.failed("导入失败，所有订单号均已存在于数据库中");
            }


            // 分别记录成功插入、插入失败、重复的订单号
            List<String> successOrders = new ArrayList<>();
            List<String> failedOrders = new ArrayList<>();
            List<String> duplicateOrders = new ArrayList<>(existingOrderCodes); // 重复的订单号

            // 插入第一张表（过滤后的订单号）的数据到数据库
            for (PurchaseOrderEntity order : nonExistingOrders) {
                if (order != null) {
                    int insert = purchaseOrderMapper.insert(order);
                    if (insert == 1) {
                        successOrders.add(order.getOrderCode());
                    } else {
                        failedOrders.add(order.getOrderCode());
                    }
                }
            }

            // 重置输入流，读取第二个 sheet（订单项）
            InputStream orderItemStream = file.getInputStream();

            ImportParams orderParams = new ImportParams();
            orderParams.setHeadRows(1); // 设置表头为1行
            orderParams.setStartSheetIndex(1); // 读取第二个 sheet

            List<OrderItemEntity> orderItems = ExcelImportUtil.importExcel(orderItemStream, OrderItemEntity.class, orderParams);

            // 检查第二张 sheet 数据是否为空
            if (orderItems == null || orderItems.isEmpty()) {
                return R.failed("导入失败，第二张表没有数据");
            }

            // 插入第二张表（订单项）的数据到数据库
            for (OrderItemEntity item : orderItems) {
                if (item != null) {
                    int insert = orderItemMapper.insert(item);
                    if (insert != 1) {
                        return R.failed("导入失败，插入订单项数据失败");
                    }
                }
            }

            // 返回成功、失败和重复订单号的响应
            String resultMessage = String.format("导入完成，成功的订单号: %s, 插入失败的订单号: %s, 重复的订单号: %s",
                    successOrders.isEmpty() ? "无" : String.join(", ", successOrders),
                    failedOrders.isEmpty() ? "无" : String.join(", ", failedOrders),
                    duplicateOrders.isEmpty() ? "无" : String.join(", ", duplicateOrders));

            return R.ok(resultMessage);

        } catch (Exception e) {
            e.printStackTrace();
            return R.failed("导入失败: " + e.getMessage());
        }
    }


    /**
     * 采购订单的模板下载
     */

    public byte[] orderTemplate() throws IOException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        // 创建 ExcelWriter
        ExcelWriter writer = EasyExcel.write(outputStream).build();

        // 创建一个空的数据列表，只导出表头
        List<MaterialZmaraEntity> emptyList = new ArrayList<>();

        // 第一个工作表
        WriteSheet purchaseOrderSheet = EasyExcel.writerSheet("采购订单")
                .head(PurchaseOrderEntity.class)
                .build();
        writer.write(emptyList, purchaseOrderSheet); // 写入空列表以生成表头

        // 第二个工作表
        WriteSheet orderItemSheet = EasyExcel.writerSheet("采购订单行项目")
                .head(OrderItemEntity.class)
                .build();
        writer.write(emptyList, orderItemSheet); // 写入空列表以生成表头

        // 关闭 writer
        writer.finish();

        // 将字节流转换为字节数组并返回
        return outputStream.toByteArray();
    }


}




















